package com.eshop.utils;

import java.util.Set;
import java.util.Map;
import java.util.Collection;
import java.util.Collections;
import org.springframework.util.CollectionUtils;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisConnectionUtils;
import java.util.ArrayList;
import java.util.Objects;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.ScanOptions;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class RedisUtils
{
    private RedisTemplate<Object, Object> redisTemplate;
    @Value("${jwt.online-key}")
    private String onlineKey;
    
    public RedisUtils(final RedisTemplate<Object, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
    
    public boolean expire(final String key, final long time) {
        try {
            if (time > 0L) {
                this.redisTemplate.expire((Object)key, time, TimeUnit.SECONDS);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    
    public long getExpire(final Object key) {
        return this.redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }
    
    public List<String> scan(final String pattern) {
        final ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
        final RedisConnectionFactory factory = this.redisTemplate.getConnectionFactory();
        final RedisConnection rc = Objects.requireNonNull(factory).getConnection();
        final Cursor<byte[]> cursor = (Cursor<byte[]>)rc.scan(options);
        final List<String> result = new ArrayList<String>();
        while (cursor.hasNext()) {
            result.add(new String((byte[])cursor.next()));
        }
        try {
            RedisConnectionUtils.releaseConnection(rc, factory);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    
    public List<String> findKeysForPage(final String patternKey, final int page, final int size) {
        final ScanOptions options = ScanOptions.scanOptions().match(patternKey).build();
        final RedisConnectionFactory factory = this.redisTemplate.getConnectionFactory();
        final RedisConnection rc = Objects.requireNonNull(factory).getConnection();
        final Cursor<byte[]> cursor = (Cursor<byte[]>)rc.scan(options);
        final List<String> result = new ArrayList<String>(size);
        int tmpIndex = 0;
        final int fromIndex = page * size;
        final int toIndex = page * size + size;
        while (cursor.hasNext()) {
            if (tmpIndex >= fromIndex && tmpIndex < toIndex) {
                result.add(new String((byte[])cursor.next()));
                ++tmpIndex;
            }
            else {
                if (tmpIndex >= toIndex) {
                    break;
                }
                ++tmpIndex;
                cursor.next();
            }
        }
        try {
            RedisConnectionUtils.releaseConnection(rc, factory);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    
    public boolean hasKey(final String key) {
        try {
            return this.redisTemplate.hasKey((Object)key);
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public void del(final String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                this.redisTemplate.delete((Object)key[0]);
            }
            else {
                this.redisTemplate.delete((Object)CollectionUtils.arrayToList((Object)key));
            }
        }
    }
    
    public Object get(final String key) {
        return (key == null) ? null : this.redisTemplate.opsForValue().get((Object)key);
    }
    
    public String getY(final String key) {
        return (key == null || !this.redisTemplate.hasKey((Object)key)) ? "" : this.redisTemplate.opsForValue().get((Object)key).toString();
    }
    
    public List<Object> multiGet(final List<String> keys) {
        final Object obj = this.redisTemplate.opsForValue().multiGet((Collection)Collections.singleton(keys));
        return null;
    }
    
    public boolean set(final String key, final Object value) {
        try {
            this.redisTemplate.opsForValue().set((Object)key, value);
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public boolean set(final String key, final Object value, final long time) {
        try {
            if (time > 0L) {
                this.redisTemplate.opsForValue().set((Object)key, value, time, TimeUnit.SECONDS);
            }
            else {
                this.set(key, value);
            }
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public boolean set(final String key, final Object value, final long time, final TimeUnit timeUnit) {
        try {
            if (time > 0L) {
                this.redisTemplate.opsForValue().set((Object)key, value, time, timeUnit);
            }
            else {
                this.set(key, value);
            }
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public Object hget(final String key, final String item) {
        return this.redisTemplate.opsForHash().get((Object)key, (Object)item);
    }
    
    public Map<Object, Object> hmget(final String key) {
        return (Map<Object, Object>)this.redisTemplate.opsForHash().entries((Object)key);
    }
    
    public boolean hmset(final String key, final Map<String, Object> map) {
        try {
            this.redisTemplate.opsForHash().putAll((Object)key, (Map)map);
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public boolean hmset(final String key, final Map<String, Object> map, final long time) {
        try {
            this.redisTemplate.opsForHash().putAll((Object)key, (Map)map);
            if (time > 0L) {
                this.expire(key, time);
            }
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public boolean hset(final String key, final String item, final Object value) {
        try {
            this.redisTemplate.opsForHash().put((Object)key, (Object)item, value);
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public boolean hset(final String key, final String item, final Object value, final long time) {
        try {
            this.redisTemplate.opsForHash().put((Object)key, (Object)item, value);
            if (time > 0L) {
                this.expire(key, time);
            }
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public void hdel(final String key, final Object... item) {
        this.redisTemplate.opsForHash().delete((Object)key, item);
    }
    
    public boolean hHasKey(final String key, final String item) {
        return this.redisTemplate.opsForHash().hasKey((Object)key, (Object)item);
    }
    
    public double hincr(final String key, final String item, final double by) {
        return this.redisTemplate.opsForHash().increment((Object)key, (Object)item, by);
    }
    
    public double hdecr(final String key, final String item, final double by) {
        return this.redisTemplate.opsForHash().increment((Object)key, (Object)item, -by);
    }
    
    public Set<Object> sGet(final String key) {
        try {
            return (Set<Object>)this.redisTemplate.opsForSet().members((Object)key);
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public boolean sHasKey(final String key, final Object value) {
        try {
            return this.redisTemplate.opsForSet().isMember((Object)key, value);
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public long sSet(final String key, final Object... values) {
        try {
            return this.redisTemplate.opsForSet().add((Object)key, values);
        }
        catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }
    
    public long sSetAndTime(final String key, final long time, final Object... values) {
        try {
            final Long count = this.redisTemplate.opsForSet().add((Object)key, values);
            if (time > 0L) {
                this.expire(key, time);
            }
            return count;
        }
        catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }
    
    public long sGetSetSize(final String key) {
        try {
            return this.redisTemplate.opsForSet().size((Object)key);
        }
        catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }
    
    public long setRemove(final String key, final Object... values) {
        try {
            final Long count = this.redisTemplate.opsForSet().remove((Object)key, values);
            return count;
        }
        catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }
    
    public List<Object> lGet(final String key, final long start, final long end) {
        try {
            return (List<Object>)this.redisTemplate.opsForList().range((Object)key, start, end);
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public long lGetListSize(final String key) {
        try {
            return this.redisTemplate.opsForList().size((Object)key);
        }
        catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }
    
    public Object lGetIndex(final String key, final long index) {
        try {
            return this.redisTemplate.opsForList().index((Object)key, index);
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public boolean lSet(final String key, final Object value) {
        try {
            this.redisTemplate.opsForList().rightPush((Object)key, value);
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public boolean lSet(final String key, final Object value, final long time) {
        try {
            this.redisTemplate.opsForList().rightPush((Object)key, value);
            if (time > 0L) {
                this.expire(key, time);
            }
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public boolean lSet(final String key, final List<Object> value) {
        try {
            this.redisTemplate.opsForList().rightPushAll((Object)key, (Collection)value);
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public boolean lSet(final String key, final List<Object> value, final long time) {
        try {
            this.redisTemplate.opsForList().rightPushAll((Object)key, (Collection)value);
            if (time > 0L) {
                this.expire(key, time);
            }
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public boolean lUpdateIndex(final String key, final long index, final Object value) {
        try {
            this.redisTemplate.opsForList().set((Object)key, index, value);
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public long lRemove(final String key, final long count, final Object value) {
        try {
            return this.redisTemplate.opsForList().remove((Object)key, count, value);
        }
        catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }
}
